﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using MessageBox = System.Windows.MessageBox;

namespace ZiMuGenerator
{
    public class MainWindowViewModel : DependencyObject, INotifyPropertyChanged
    {
        #region 构造

        public MainWindowViewModel()
        {
            var isInDesignMode = DesignerProperties.GetIsInDesignMode(this);
            if (isInDesignMode)
            {
                return;
            }

            InitCommands();

            SetStateBarText("加载字模...");
            m_Service = new ZiMuService();
            m_Service.InitProgressChanged += Service_ProgressChanged;
            m_Service.InitFinished += Service_InitFinished;
            m_Service.InitException += Service_InitException;

            m_Service.SaveProgressChanged += Service_SaveProgressChanged;
            m_Service.SaveFinished += Service_SaveFinished;
            m_Service.SaveException += Service_SaveException;

            m_Service.BeginInit();
        }

        #endregion


        #region 私有成员

        private string m_Input = "字帖";
        private char m_LastInputFirstWord = '字'; // 记录上次输入内容的第一个字，用于判断是否需要刷新字帖预览

        private int m_WordSize = 120;
        private int m_BorderSize = 4;

        private SolidColorBrush m_FillColor = new SolidColorBrush(Colors.Red);
        private SolidColorBrush m_BorderColor = new SolidColorBrush(Colors.Black);
        private SolidColorBrush m_BackColor = new SolidColorBrush(Colors.Yellow);

        private Visibility m_ProgressBarVisibility = Visibility.Visible;
        private double m_Progree = 30.0;
        private string m_ProgreeText = "30%";
        private string m_StatusBarText = "就绪";

        private BitmapImage m_PreviewImage;

        private DelegateCommand m_TextChanged;
        private DelegateCommand m_BorderColorLableClicked;
        private DelegateCommand m_FillColorLableClicked;
        private DelegateCommand m_BackColorLableClicked;
        private DelegateCommand m_BrowseFolderButtonClicked;
        private DelegateCommand m_OpenSaveFolderButtonClicked;
        private DelegateCommand m_GenerateButtonClicked;
        private DelegateCommand m_GenerateParamsChanged;
        private DelegateCommand<string> m_WordSizeTextChanged;
        private DelegateCommand<string> m_BorderSizeTextChanged;

        private string m_SaveFolderPath = Environment.CurrentDirectory;

        private bool m_IsBorderColorTransparent;
        private bool m_IsFillColorTransparent;
        private bool m_IsBackColorTransparent;
        private bool m_IsGenerateAllPaths = true;


        public int m_WordCountPerRow = 8;
        public int m_WordMargin = 16;
        public bool m_IsSplitWords = true;
        public DelegateCommand m_SavePreviewImage;

        private ZiMuService m_Service;

        #endregion


        #region 属性

        /// <summary>
        /// 用户输入的内容
        /// </summary>
        public string Input
        {
            get => m_Input;
            set
            {
                m_Input = value;
                OnPropertyChanged();
            }
        }


        /// <summary>
        /// 文字边长
        /// </summary>
        public int WordSize
        {
            get => m_WordSize;
            set
            {
                m_WordSize = value;
                OnPropertyChanged();
                Cmd_GenerateParamsChanged();
            }
        }

        /// <summary>
        /// 描边大小
        /// </summary>
        public int BorderSize
        {
            get => m_BorderSize;
            set
            {
                m_BorderSize = value;
                OnPropertyChanged();
                Cmd_GenerateParamsChanged();
            }
        }


        /// <summary>
        /// 边框颜色
        /// </summary>
        public SolidColorBrush BorderColor
        {
            get => m_BorderColor;
            set
            {
                m_BorderColor = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// 填充颜色
        /// </summary>
        public SolidColorBrush FillColor
        {
            get => m_FillColor;
            set
            {
                m_FillColor = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// 背景颜色
        /// </summary>
        public SolidColorBrush BackColor
        {
            get => m_BackColor;
            set
            {
                m_BackColor = value;
                OnPropertyChanged();
            }
        }


        /// <summary>
        /// 进度条是否可见
        /// </summary>
        public Visibility ProgreeBarVisibility
        {
            get => m_ProgressBarVisibility;
            set
            {
                m_ProgressBarVisibility = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// 进度条进度
        /// </summary>
        public double Progress
        {
            get => m_Progree;
            set
            {
                m_Progree = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// 进度条现实内容
        /// </summary>
        public string ProgressText
        {
            get => m_ProgreeText;
            set
            {
                m_ProgreeText = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// 状态条内容
        /// </summary>
        public string StatusBarText
        {
            get => m_StatusBarText;
            set
            {
                m_StatusBarText = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// 字帖预览
        /// </summary>
        public BitmapImage PreviewImage
        {
            get => m_PreviewImage;
            set
            {
                m_PreviewImage = value;
                OnPropertyChanged();
            }
        }


        public DelegateCommand TextChanged
        {
            get => m_TextChanged;
            set
            {
                m_TextChanged = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand BorderColorLableClicked
        {
            get => m_BorderColorLableClicked;
            set
            {
                m_BorderColorLableClicked = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand FillColorLableClicked
        {
            get => m_FillColorLableClicked;
            set
            {
                m_FillColorLableClicked = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand BackColorLableClicked
        {
            get => m_BackColorLableClicked;
            set
            {
                m_BackColorLableClicked = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand BrowseFolderButtonClicked
        {
            get => m_BrowseFolderButtonClicked;
            set
            {
                m_BrowseFolderButtonClicked = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand OpenSaveFolderButtonClicked
        {
            get => m_OpenSaveFolderButtonClicked;
            set
            {
                m_OpenSaveFolderButtonClicked = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand GenerateButtonClicked
        {
            get => m_GenerateButtonClicked;
            set
            {
                m_GenerateButtonClicked = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand GenerateParamsChanged
        {
            get => m_GenerateParamsChanged;
            set
            {
                m_GenerateParamsChanged = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand<string> WordSizeTextChanged
        {
            get => m_WordSizeTextChanged;
            set
            {
                m_WordSizeTextChanged = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand<string> BorderSizeTextChanged
        {
            get => m_BorderSizeTextChanged;
            set
            {
                m_BorderSizeTextChanged = value;
                OnPropertyChanged();
            }
        }


        /// <summary>
        /// 字模生成保存路径
        /// </summary>
        public string SaveFolderPath
        {
            get => m_SaveFolderPath;
            set
            {
                m_SaveFolderPath = value;
                OnPropertyChanged();
            }
        }

        public bool IsBorderColorTransparent
        {
            get => m_IsBorderColorTransparent;
            set
            {
                m_IsBorderColorTransparent = value;
                OnPropertyChanged();
            }
        }

        public bool IsFillColorTransparent
        {
            get => m_IsFillColorTransparent;
            set
            {
                m_IsFillColorTransparent = value;
                OnPropertyChanged();
            }
        }

        public bool IsBackColorTransparent
        {
            get => m_IsBackColorTransparent;
            set
            {
                m_IsBackColorTransparent = value;
                OnPropertyChanged();
            }
        }

        public bool IsGenerateAllPaths
        {
            get => m_IsGenerateAllPaths;
            set
            {
                m_IsGenerateAllPaths = value;
                OnPropertyChanged();
            }
        }


        public int WordCountPerRow
        {
            get => m_WordCountPerRow;
            set
            {
                m_WordCountPerRow = value;
                OnPropertyChanged();
            }
        }

        public int WordMargin
        {
            get => m_WordMargin;
            set
            {
                m_WordMargin = value;
                OnPropertyChanged();
            }
        }

        public bool IsSplitWords
        {
            get => m_IsSplitWords;
            set
            {
                m_IsSplitWords = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand SavePreviewImage
        {
            get => m_SavePreviewImage;
            set
            {
                m_SavePreviewImage = value;
                OnPropertyChanged();
            }
        }

        #endregion


        #region 事件

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 属性改变
        /// </summary>
        /// <param name="propertyName">属性名，可空，留空表示获取调用的方法名</param>
        public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private void Service_InitException(object sender, string e)
        {
            System.Windows.MessageBox.Show($"初始化字模列表异常：{e}");
            Environment.Exit(0);
        }

        private void Service_InitFinished(object sender, EventArgs e)
        {
            SetStateBarText("就绪");
            Dispatcher.Invoke(new Action(() => { Cmd_GenerateParamsChanged(); }));
        }

        private void Service_ProgressChanged(object sender, int e)
        {
            SetProgressValue(e);
        }

        private void Service_SaveException(object sender, string e)
        {
            System.Windows.MessageBox.Show($"保存字模出现异常：{e}");
        }

        private void Service_SaveFinished(object sender, EventArgs e)
        {
            SetStateBarText("字模生成完毕，点击\"打开生成目录\"按钮可打开保存位置");
        }

        private void Service_SaveProgressChanged(object sender, int e)
        {
            SetProgressValue(e);
        }


        private void Cmd_TextChanged()
        {
            if (Input == null)
            {
                return;
            }

            if (Input.Length >= 1)
            {
                if (Input[0] == m_LastInputFirstWord)
                {
                    return;
                }

                m_LastInputFirstWord = Input[0];
            }

            Cmd_GenerateParamsChanged();
        }

        private void Cmd_BorderColorLableClicked()
        {
            var result = ShowColorDialog(BorderColor.Color);
            if (result != null)
            {
                BorderColor = new SolidColorBrush(result.Value);
            }
        }

        private void Cmd_FillColorLableClicked()
        {
            var result = ShowColorDialog(FillColor.Color);
            if (result != null)
            {
                FillColor = new SolidColorBrush(result.Value);
            }
        }

        private void Cmd_BackColorLableClicked()
        {
            var result = ShowColorDialog(BackColor.Color);
            if (result != null)
            {
                BackColor = new SolidColorBrush(result.Value);
            }
        }

        private void Cmd_BrowseFolderButtonClicked()
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog(); //选择文件夹
            if (fbd.ShowDialog() == DialogResult.OK)
            {
                SaveFolderPath = fbd.SelectedPath;
            }
        }

        private void Cmd_OpenSaveFolderButtonClicked()
        {
            var isRoot = SaveFolderPath.Last() == '\\';
            string root;
            if (isRoot)
            {
                root = $"{SaveFolderPath}生成";
            }
            else
            {
                root = $"{SaveFolderPath}\\生成";
            }

            if (Directory.Exists(root))
            {
                Process.Start("explorer.exe", root);
                return;
            }

            ExplorerFolder(SaveFolderPath);
        }

        private void Cmd_GenerateButtonClicked()
        {
            if (!m_Service.IsInitFinished)
            {
                SetStateBarText("请等待程序初始化完毕");
                return;
            }

            if (!m_Service.IsSaveFinished)
            {
                SetStateBarText("有正在保存的任务，请稍后");
                return;
            }

            var willGenerateCharacters = Input.Replace("\r\n", string.Empty)
                .Replace("\r", string.Empty)
                .Replace("\n", string.Empty);
            if (!m_Service.CharactersVerify(willGenerateCharacters, out int invalidCharacterCount,
                out string invalidCharacters))
            {
                var message = $"输入内容中存在{invalidCharacterCount}个无效字符（括号内第一个值为字符位置，第二个值为无效的字符）：{invalidCharacters}\r\n" +
                              $"点击[是] 过滤掉无效字符并生成\r\n" +
                              $"点击[否] 取消生成操作";
                if (System.Windows.MessageBox.Show(message, "提示", MessageBoxButton.YesNo) == MessageBoxResult.No)
                {
                    return;
                }

                willGenerateCharacters = m_Service.FilterOutInvalidCharacters(Input);
            }

            DoGenerate(willGenerateCharacters);
        }

        private void Cmd_GenerateParamsChanged()
        {
            if (!m_Service.IsInitFinished)
            {
                //SetStateBarText("请等待程序初始化完毕");
                return;
            }

            m_Service.WordSize = WordSize;
            m_Service.StrokeWidth = BorderSize;
            m_Service.IsGenerateAllPaths = IsGenerateAllPaths;
            if (IsBorderColorTransparent)
            {
                m_Service.StrokeColor = new Svg.SvgColourServer(ToDrawingColor(Colors.Transparent));
            }
            else
            {
                m_Service.StrokeColor = new Svg.SvgColourServer(ToDrawingColor(BorderColor.Color));
            }

            if (IsFillColorTransparent)
            {
                m_Service.FillColor = new Svg.SvgColourServer(ToDrawingColor(Colors.Transparent));
            }
            else
            {
                m_Service.FillColor = new Svg.SvgColourServer(ToDrawingColor(FillColor.Color));
            }

            if (IsBackColorTransparent)
            {
                m_Service.BackgroundColor = new SolidBrush(ToDrawingColor(Colors.Transparent));
            }
            else
            {
                m_Service.BackgroundColor = new SolidBrush(ToDrawingColor(BackColor.Color));
            }

            if (Input == null)
            {
                PreviewImage = ToBitmapImage(m_Service.GetPreviewImage('字'));
            }

            bool isFound = false;
            for (int i = 0; i < Input.Length; i++)
            {
                if (m_Service.ZiMuDictionary.ContainsKey(Input[i]))
                {
                    PreviewImage = ToBitmapImage(m_Service.GetPreviewImage(Input[i]));
                    isFound = true;
                    break;
                }
            }

            if (!isFound)
            {
                PreviewImage = ToBitmapImage(m_Service.GetPreviewImage('字'));
            }
        }


        private void Cmd_WordSizeTextChanged(string text)
        {
            if (text == null || text.Length == 0)
            {
                WordSize = 1;
                return;
            }

            if (int.TryParse(text, out int result))
            {
                WordSize = result;
            }
            else
            {
                WordSize = 1;
            }
        }

        private void Cmd_BorderSizeTextChanged(string text)
        {
            if (text == null || text.Length == 0)
            {
                BorderSize = 0;
                return;
            }

            if (int.TryParse(text, out int result))
            {
                BorderSize = result;
            }
            else
            {
                BorderSize = 1;
            }
        }


        private void Cmd_SavePreviewImage()
        {
            if (PreviewImage == null)
            {
                MessageBox.Show("无预览图");
                return;
            }

            if (WordCountPerRow < 1)
            {
                MessageBox.Show("每行字数不能小于1个");
                return;
            }

            if (WordMargin < 0)
            {
                MessageBox.Show("字间距不能小于0");
                return;
            }

            var dialog = new SaveFileDialog();
            dialog.DefaultExt = ".jpg";
            dialog.FileName = $"字帖_{DateTime.Now:yyyyMMdd_hhmmss}";
            dialog.Filter = "图片(*.jpg)|*.jpg|所有文件(*.*)|*.*";
            dialog.InitialDirectory = SaveFolderPath;
            if (dialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            m_Service.WordCountPerRow = WordCountPerRow;
            m_Service.ColumnMargin = WordMargin;
            m_Service.RowMargin = WordMargin;
            var bmp = m_Service.GetFullPreviewImage(Input, !IsSplitWords);
            if (bmp == null)
            {
                MessageBox.Show("生成预览图失败");
                return;
            }

            try
            {
                bmp.Save(dialog.FileName);
            }
            catch (Exception e)
            {
                MessageBox.Show($"保存预览图失败，异常信息：{e.Message}");
                return;
            }

            if (MessageBox.Show("保存成功！是否打开图片？", "提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                ViewImage(dialog.FileName);
            }
        }

        #endregion


        #region 操作

        private void InitCommands()
        {
            TextChanged = new DelegateCommand
            {
                ExecuteAction = Cmd_TextChanged
            };

            BorderColorLableClicked = new DelegateCommand
            {
                ExecuteAction = Cmd_BorderColorLableClicked
            };

            FillColorLableClicked = new DelegateCommand
            {
                ExecuteAction = Cmd_FillColorLableClicked
            };

            BackColorLableClicked = new DelegateCommand
            {
                ExecuteAction = Cmd_BackColorLableClicked
            };

            BrowseFolderButtonClicked = new DelegateCommand
            {
                ExecuteAction = Cmd_BrowseFolderButtonClicked
            };

            OpenSaveFolderButtonClicked = new DelegateCommand
            {
                ExecuteAction = Cmd_OpenSaveFolderButtonClicked
            };

            GenerateButtonClicked = new DelegateCommand
            {
                ExecuteAction = Cmd_GenerateButtonClicked
            };

            GenerateParamsChanged = new DelegateCommand
            {
                ExecuteAction = Cmd_GenerateParamsChanged
            };

            WordSizeTextChanged = new DelegateCommand<string>
            {
                ExecuteAction = Cmd_WordSizeTextChanged
            };

            BorderSizeTextChanged = new DelegateCommand<string>
            {
                ExecuteAction = Cmd_BorderSizeTextChanged
            };

            SavePreviewImage = new DelegateCommand(Cmd_SavePreviewImage);
        }


        private static void ViewImage(string path)
        {
            Process.Start(path);
        }
        
        private static void ExplorerFolder(string path)
        {
            Process.Start("explorer.exe", path);
        }

        private void SetProgressValue(int value)
        {
            if (value < 0)
            {
                value = 0;
            }

            if (value > 100)
            {
                value = 100;
            }

            Dispatcher.Invoke(new Action(() =>
            {
                if (value == 0 || value == 100)
                {
                    if (ProgreeBarVisibility != Visibility.Collapsed)
                    {
                        ProgreeBarVisibility = Visibility.Collapsed;
                    }
                }
                else
                {
                    if (ProgreeBarVisibility != Visibility.Visible)
                    {
                        ProgreeBarVisibility = Visibility.Visible;
                    }

                    if (Progress != value)
                    {
                        Progress = value;
                    }

                    var pro = $"{value}%";
                    if (ProgressText != pro)
                    {
                        ProgressText = pro;
                        Debug.WriteLine(pro);
                    }
                }
            }));
        }

        private void SetStateBarText(string value)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                if (StatusBarText != value)
                {
                    StatusBarText = value;
                }
            }));
        }

        public static BitmapImage ToBitmapImage(Bitmap bitmap)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                bitmap.Save(stream, ImageFormat.Png); // 坑点：格式选Bmp时，不带透明度

                stream.Position = 0;
                BitmapImage result = new BitmapImage();
                result.BeginInit();
                // According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."
                // Force the bitmap to load right now so we can dispose the stream.
                result.CacheOption = BitmapCacheOption.OnLoad;
                result.StreamSource = stream;
                result.EndInit();
                result.Freeze();
                return result;
            }
        }

        /// <summary>
        /// 把内存里的BitmapImage数据保存到硬盘中
        /// </summary>
        /// <param name="bitmapImage">BitmapImage数据</param>
        /// <param name="filePath">输出的文件路径</param>
        public static void SaveBitmapImageIntoFile(BitmapImage bitmapImage, string filePath)
        {
            BitmapEncoder encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(bitmapImage));

            using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
            {
                encoder.Save(fileStream);
            }
        }

        private System.Windows.Media.Color? ShowColorDialog(System.Windows.Media.Color? lastColor)
        {
            ColorDialog ColorForm = new ColorDialog();
            if (lastColor != null)
            {
                ColorForm.Color = ToDrawingColor(lastColor.Value);
            }

            if (ColorForm.ShowDialog() == DialogResult.OK)
            {
                return ToMediaColor(ColorForm.Color);
            }

            return null;
        }


        private System.Drawing.Color ToDrawingColor(System.Windows.Media.Color color)
        {
            var c = System.Drawing.Color.FromArgb(
                color.A,
                color.R,
                color.G,
                color.B);
            return c;
        }

        private System.Windows.Media.Color ToMediaColor(System.Drawing.Color color)
        {
            System.Windows.Media.Color c = new System.Windows.Media.Color();
            c.R = color.R;
            c.G = color.G;
            c.B = color.B;
            c.A = color.A;
            return c;
        }


        private void DoGenerate(string text)
        {
            try
            {
                var root = $"{SaveFolderPath}\\生成";
                if (Directory.Exists(root))
                {
                    Directory.Delete(root, true);
                }

                Directory.CreateDirectory(root);
                m_Service.SaveRoot = root;

                m_Service.ParseAndSave(text);
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show($"创建目录出现异常，异常信息：{ex.Message}\r\n" +
                                               $"可能的解决方法：\r\n" +
                                               $"1、修改输出目录\r\n" +
                                               $"2、使用管理员权限运行本程序");
            }
        }

        #endregion
    }
}